package pt.compflow.storage;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hp.hpl.jena.graph.Graph;
import com.hp.hpl.jena.sdb.SDBFactory;
import com.hp.hpl.jena.sdb.Store;
import com.hp.hpl.jena.sdb.StoreDesc;
import com.hp.hpl.jena.sdb.sql.MySQLEngineType;
import com.hp.hpl.jena.sdb.store.DatabaseType;
import com.hp.hpl.jena.sdb.store.LayoutType;
import com.hp.hpl.jena.sdb.util.StoreUtils;

public class SDBTripleStoreConnection extends TripleStoreConnectionBase implements TripleStoreConnection {

	private static final Logger LOG = LoggerFactory.getLogger(SDBTripleStoreConnection.class);

	protected Store store;

	public SDBTripleStoreConnection() {
		super();
		
		try {
			Properties engineProperties = new Properties();
			engineProperties.load(SDBTripleStoreConnection.class.getResourceAsStream("/engine.properties"));
			setConfig(engineProperties);
		} catch (IOException e) {
			LOG.error("Error loading engine.properties", e);
		}
	}
	
	public SDBTripleStoreConnection(Properties config) {
		super(config);
	}
	
	public void openStore() {
		openStore(null);
	}

	public void openStore(Connection conn) {
		// close store if open; a new store will be open
		if (store != null) closeStore();
		
//		LOG.debug("[SDB-CONN] Opening Store/Connection");

		// TripleStore descriptor set to use MySQL engine
		StoreDesc desc = new StoreDesc(LayoutType.LayoutTripleNodesHash, DatabaseType.MySQL);
		desc.engineType = MySQLEngineType.MyISAM;
		if(conn == null) conn = getJdbcConnection();
	
		// connect to TripleStore using MySQL JDBC connection
		if (conn == null) return;
		store = SDBFactory.connectStore(conn, desc);
		
		try {
			if (!StoreUtils.isFormatted(store)) {
				// format MySQL database for according to the SDB profile
				LOG.debug("[SDB-INIT] Initializing SDB Triple Store...");
				store.getTableFormatter().create();
			}
		} catch (SQLException e) {
			LOG.error("[SDB-INIT] Unable to Initialize SDB Triple Store", e);
			closeStore();
		}
	}

	public void closeStore() {
//		LOG.debug("[SDB-CONN] Closing Store/Connection");
		if (store != null)
			store.close();
		store = null;
	}

	@Override
	public Graph connectGraph() {
		return SDBFactory.connectDefaultGraph(store);
	}

	@Override
	public Graph connectNamedGraph(String iri) {
		return SDBFactory.connectNamedGraph(store, iri);
	}
	
	public Store getStore() {
		return store;
	}
	
	/**
	 * Get a MySQL JDBC connection with the parameters found in the config file
	 * @return the JDBC connection or null if an error occurs
	 * 
	 */
	protected Connection getJdbcConnection() {
		// check driver availability
		try {
			Class.forName("com.mysql.jdbc.Driver").newInstance();
		} catch (Exception e) {
			LOG.error("[JDBC-CONN] Unable to Establish Database Connection", e);
			return null;
		}
		
		// check config properties
		if(config == null) {
			LOG.error("[JDBC-CONN] Unable to Establish Database Connection: properties are not defined!");
			return null;
		}
		
		// establish connection
		try {
			String port = "3306";
			if(config.getProperty("jdbcPort") != null) port = config.getProperty("jdbcPort");
			String url = "jdbc:" + config.getProperty("jdbcSystem") + "://" + config.getProperty("jdbcHost") + ":" + port + "/" + config.getProperty("jdbcDatabase");
			return DriverManager.getConnection(url, config.getProperty("jdbcUsername"), config.getProperty("jdbcPassword"));
		} catch (Exception e) {
			LOG.error("[JDBC-CONN] Unable to Establish Database Connection", e);
			return null;
		}
	}

}